#include "Filesystem.hpp"

#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>

namespace fs = boost::filesystem;

bool FileHelper::Exists(const std::string& path)
{
	return boost::filesystem::exists(path);
}

bool FileHelper::IsDirectory(const std::string& path)
{
	return boost::filesystem::is_directory(path);
}

bool FileHelper::CreatePath(const std::string& path)
{
	if (!boost::filesystem::exists(path))
		return boost::filesystem::create_directories(path);
	else
		return true;
}

void FileHelper::EnumerateFiles(const std::string& path, std::vector<std::string>& files, const std::string& regex)
{
	namespace fs = boost::filesystem;
	fs::path path_(path);//, fs::native);
	if (!fs::exists(path_))
		return;

	std::regex regex_;
	FileHelper::ParseRegex(regex, regex_);

	fs::recursive_directory_iterator end;
	files.clear();
	for (fs::recursive_directory_iterator it(path_); it != end; ++it)
	{
		try
		{
			if (fs::is_directory(*it))
				continue;

			if (std::regex_match(it->path().filename().string(), regex_))
			{
				files.push_back(it->path().string());
			}
		}
		catch (std::exception& ex)
		{
			//HY_LOG_E("load images catch exception: {}", ex.what());
			std::cout << std::format("load images catch exception: {}", ex.what());
		}
	}
	std::sort(files.begin(), files.end());
}

void FileHelper::EnumerateSubPaths(const std::string& path, std::vector<std::string>& paths)
{
	namespace fs = boost::filesystem;
	fs::path path_(path.c_str());//, fs::native);
	if (!fs::exists(path_))
		return;
	fs::recursive_directory_iterator end;
	paths.clear();
	for (fs::recursive_directory_iterator it(path_); it != end; ++it)
	{
		try
		{
			if (!fs::is_directory(*it))
				continue;
			else
				paths.push_back(it->path().string());
		}
		catch (std::exception& ex)
		{
			//HY_LOG_E("load images catch exception: {}", ex.what());
			std::cout << std::format("load images catch exception: {}", ex.what());
		}
	}
}

std::string FileHelper::LowerExtension(const std::string& file)
{
	std::string extension;
	if (file.empty() || boost::filesystem::is_directory(file))
		return extension;

	boost::filesystem::path path(file);
	if (path.has_extension())
	{
		extension = boost::algorithm::to_lower_copy(path.extension().generic_string());
	}
	return extension;
}

std::string FileHelper::ExcludeExtension(const std::string& file)
{
	boost::filesystem::path path(file);
	//std::cout << path.stem().string() << std::endl;
	std::cout << std::format("the path of file exclude extension is {}.", path.stem().string()) << std::endl;
	return path.stem().string();
}

//bool FileHelper::Exists(const std::wstring& path)
//{
//	return boost::filesystem::exists(path);
//}
//
//bool FileHelper::CreatePath(const std::wstring& path)
//{
//	if (!boost::filesystem::exists(path))
//		return boost::filesystem::create_directories(path);
//	else
//		return true;
//}
//
//void FileHelper::EnumerateFiles(const std::wstring& path, std::vector<std::wstring>& files, const std::string& regex)
//{
//	namespace fs = boost::filesystem;
//	fs::path path_(path);//, fs::native);
//	if (!fs::exists(path_))
//		return;
//
//	std::regex regex_;
//	FileHelper::ParseRegex(regex, regex_);
//
//	fs::recursive_directory_iterator end;
//	files.clear();
//	for (fs::recursive_directory_iterator it(path_); it != end; ++it)
//	{
//		try
//		{
//			if (fs::is_directory(*it))
//				continue;
//
//			if (std::regex_match(it->path().filename().string(), regex_))
//			{
//				files.push_back(it->path().wstring());
//				break;
//			}
//		}
//		catch (std::exception& ex)
//		{
//			HY_LOG_SEV(error) << "load images catch exception: " << ex.what();
//		}
//	}
//	std::sort(files.begin(), files.end());
//}
//
//void FileHelper::EnumerateSubPaths(const std::wstring& path, std::vector<std::wstring>& paths)
//{
//	namespace fs = boost::filesystem;
//	fs::path path_(path.c_str());//, fs::native);
//	if (!fs::exists(path_))
//		return;
//	fs::recursive_directory_iterator end;
//	paths.clear();
//	for (fs::recursive_directory_iterator it(path_); it != end; ++it)
//	{
//		try
//		{
//			if (!fs::is_directory(*it))
//				continue;
//			else
//				paths.push_back(it->path().wstring());
//		}
//		catch (std::exception& ex)
//		{
//			HY_LOG_SEV(error) << "load images catch exception: " << ex.what();
//		}
//	}
//}

bool FileHelper::ZipPath(const std::string& path, const std::string& file, const std::string& regex)
{
	std::vector<std::string> files;
	FileHelper::EnumerateFiles(path, files, regex);
	if (files.size() == 0)
		return false;

	mz_zip_archive zip_archive;
	memset(&zip_archive, 0, sizeof(zip_archive));
	mz_bool status = mz_zip_writer_init_file(&zip_archive, file.c_str(), 0);
	if (!status)
	{
		std::cout << std::format(("open zip file {} fail", file));
		return false;
	}

	fs::recursive_directory_iterator end;
	fs::path path_(path);
	int length = path_.string().length();
	std::string name;
	bool sucess = true;
	for (int i = 0; i < files.size(); ++i)
	{
		name = files[i].substr(length + 1);
		status = mz_zip_writer_add_file(&zip_archive, name.c_str(), files[i].c_str(),
			nullptr, 0, MZ_BEST_COMPRESSION);
		if (!status)
		{
			std::cout << std::format(("add file {} to {} fail", name, file));
			sucess = false;
			break;
		}
	}

	mz_zip_writer_finalize_archive(&zip_archive);
	mz_zip_writer_end(&zip_archive);
	return sucess;
}

bool FileHelper::UnzipPath(const std::string& file, const std::string& path)
{
	if (!FileHelper::Exists(file))
	{
		std::cout << std::format(("{} is not exists", file));
		return false;
	}

	if (!FileHelper::Exists(path))
	{
		std::cout << std::format(("{} is not exists", path));
		return false;
	}

	mz_zip_archive zip_archive;
	memset(&zip_archive, 0, sizeof(zip_archive));
	mz_bool status = mz_zip_reader_init_file(&zip_archive, file.c_str(), 0);
	if (!status)
	{
		std::cout << std::format(("open zip file {} fail", file));
		return false;
	}

	size_t count = mz_zip_reader_get_num_files(&zip_archive);
	if (count == 0)
	{
		mz_zip_reader_end(&zip_archive);
		return true;
	}

	mz_zip_archive_file_stat file_stat;
	std::string name;
	bool sucess = true;
	for (size_t i = 0; i < count; ++i)
	{
		if (!mz_zip_reader_file_stat(&zip_archive, i, &file_stat))
		{
			sucess = false;
			break;
		}

		if (mz_zip_reader_is_file_a_directory(&zip_archive, i))
		{
			continue;
		}

		name = path + "/" + file_stat.m_filename;
		fs::path path_(name);
		FileHelper::CreatePath(path_.parent_path().string());

		status = mz_zip_reader_extract_file_to_file(&zip_archive, file_stat.m_filename, name.c_str(), 0);
		if (!status)
		{
			std::cout << std::format(("extract file {} to {} fail", file_stat.m_filename, path));
			sucess = false;
			break;
		}
		//HY_LOG_SEV(debug) << boost::format("extract file %1% to %2%")
		//	% file_stat.m_filename % path;
	}

	mz_zip_reader_end(&zip_archive);
	return true;
}

void FileHelper::ParseRegex(const std::string& script, std::regex& regex)
{
	try
	{
		regex = std::regex(script);
	}
	catch (const std::exception& ex)
	{
		std::cout << std::format(("parse regex script {} catch exception: {}", script, ex.what()));
		regex = std::regex(" ^ .*$");
	}
}
